/******************************************************************************/
/***                                                                        ***/
/***  InitMaster.c                                                          ***/
/***                                                                        ***/
/***  This program will initalise a 'Software Protection Scheme's' Master   ***/
/***  with the specific information required for the application.           ***/
/***                                                                        ***/
/***  The variables are defined in the SPDefs.h file, by changing any of    ***/
/***  these values will the Software Protection unique to these items, thus ***/
/***  all applications can have a differnet protection. The values are used ***/
/***  to compute constants which become part of the code, thus providing    ***/
/***  better code protection.                                               ***/
/***                                                                        ***/
/***  This proram first encodes and stores the configuation file with the   ***/
/***  value 'FFFFFFFFFFFFFF' which indicates the system has not been        ***/
/***  configured yet, in the application directory. It also stores a        ***/
/***  default registration number and default licence holder string, but    ***/
/***  will always be altered the first time the application is confifured.  ***/
/***                                                                        ***/
/***                                                                        ***/
/***  Written by N.Critchell, Acorn Computers                   April 1992  ***/
/***                                             Updated -  11 August 1992  ***/
/***                                                                        ***/
/******************************************************************************/

 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>

 #include "kernel.h"

 #include "SProutines.h"
 #include "SPDefs.h"


 #define ADFS_DiscOpErrors       (ADFS_DiscOp | _kernel_NONX)
 #define ADFS_DescribeDiscErrors (ADFS_DescribeDisc | _kernel_NONX)



 void WriteEncodedInformation(ID*, REG_NO*);
 void MakeMasterDisc(ID*, REG_NO*);
 int  CreateTrack(void);
 void SaveTrackData(char *);
 void RestoreTrackData(char *);
 void make_disc_record_E_Special(char *);
 int  system_type(void);






 char Reg_Number[17];
 char LicenceHolder[40];






/******************************************************************************/
/***                                                                        ***/
/***  Main                                                                  ***/
/***                                                                        ***/
/***  The main control program.                                             ***/
/***                                                                        ***/
/******************************************************************************/


int main()
    {
    ID ID_Numbers;
    REG_NO reg_number;
    char default_Reg_Num[] = "ABCDEFGHIJK";
    char default_Licence_Holder [] = "There is no licence holder information yet!";


    ID_Numbers.ID_word[0] = 0xFFFFFFFF;
    ID_Numbers.ID_word[1] = 0xFFFFFFFF;
    strncpy((char *)&reg_number.Reg_Byte[0], default_Reg_Num, 8);
    default_Licence_Holder[0] = '\0';
    strncpy(LicenceHolder, default_Licence_Holder, 39);
    EncodeIDNumbers(&ID_Numbers);



    printf("Software Protection Scheme's Master Disc Initialiser\n\n");

    WriteEncodedInformation(&ID_Numbers, &reg_number);
    MakeMasterDisc(&ID_Numbers, &reg_number);

    exit(0);
    }






/******************************************************************************/
/***                                                                        ***/
/***  WriteEncodedInformation                                               ***/
/***                                                                        ***/
/***  Writes out the encoded ID number, the Registration Number and the     ***/
/***  Licence Holder information.                                           ***/
/***                                                                        ***/
/***  Default Values:                                                       ***/
/***    ID No.           = 0xFFFFFFFFFFFFFFFF (ie. not configured)          ***/
/***    Reg_No.          = "ABCDEFGHIJK"                                    ***/
/***    Licence Holder   = "There is no licence holder yet."                ***/
/***                                                                        ***/
/******************************************************************************/
                                                                                
void WriteEncodedInformation(ID *ID_Numbers, REG_NO *reg_number)
    {
    if (!StoreIDNumbers(ID_Numbers, reg_number))
        {
        printf("Error: Encoded information can not been written!\n\n\n");
        Belch(); 
        }
    }






/******************************************************************************/
/***                                                                        ***/
/***  MakeMasterDisc()                                                      ***/
/***                                                                        ***/
/***  Formats a disc such that it will become a master disc for use with    ***/
/***  the specified application, all information in the special sector will ***/
/***  will be initalised.                                                   ***/
/***                                                                        ***/
/***  If the disc is not formated, then it will be formatted, but all data  ***/
/***  will be saved. If the disc is already formtted, then only the special ***/
/***  sector information is written, which can be done on RISC OS 2.        ***/
/***                                                                        ***/
/******************************************************************************/
                                                                                
void MakeMasterDisc(ID *ID_Numbers, REG_NO *reg_number)
    {
    ID stored_id;
    REG_NO stored_reg;
    char track_info[(5 * 1024)];
    char sector_buffer[256];
    char disc_record[64];
    int formatted;
    int licences;
    int loop;
    int val;
    char temp_buffer[16];
    int loop1;

    formatted = (ReadIDFromMasterDisc(&stored_id, &stored_reg, -2, &val) != ID_STATUS__INVALID);
    if (!formatted)
        {
        if (system_type() >= 0xA3)
            {
            SaveTrackData(track_info);
            CreateTrack();
            RestoreTrackData(track_info);
            }
        else
            {
            printf("Error: RISC OS 3.0 or greater is required to initialise\n");
            printf("       this as a Master Disc!\n\n\n");
            Belch();
            return;
            }
        }

    
    for(loop=0; loop<256; loop++) sector_buffer[loop] = (rand() & 0xFF);


    licences = 1;
    if (MULTI_LICENCES != -1) licences = MULTI_LICENCES;

    *(int *)(temp_buffer +  0) = ID_Numbers->ID_word[0];
    *(int *)(temp_buffer +  4) = ID_Numbers->ID_word[1];
    *(int *)(temp_buffer +  8) = ID_Numbers->CheckSum[0];
    *(int *)(temp_buffer + 12) = ID_Numbers->CheckSum[1];

    for(loop=0; loop <licences; loop++)
        {
        for(loop1=0; loop1<16; loop1++)
            sector_buffer[loop1 + (loop * 16) + SECTOR_OFFSET] = temp_buffer[loop1];        
        }


    strcpy(sector_buffer, SECTOR_IDENTIFIER);
    for(loop=0; loop<10; loop++) sector_buffer[loop + REG_OFFSET] = reg_number ->Reg_Byte[loop];
    sector_buffer[LICENCE_HOLDER_OFFSET] = (char) 0;
    EorDataBlock((char *) (sector_buffer + LICENCE_HOLDER_OFFSET), 0xEA, 0x1D, 40);

    Build_Special_Disc_Record(disc_record);
    WriteSpecialSector(disc_record, sector_buffer);
    return;
    }





/******************************************************************************/
/***                                                                        ***/
/***  CreateTrack()                                                         ***/
/***                                                                        ***/
/***  Attempts to create a track of the special format.                     ***/
/***                                                                        ***/
/***  This is done by using ADFS_DiscOp to write a track (using special     ***/
/***  RISC OS 3 call, to format a track to special way.)                    ***/
/***                                                                        ***/
/***                                                                        ***/
/******************************************************************************/

int CreateTrack()
    {
    _kernel_swi_regs inregs, outregs;
    char disc_format_block[100];
    char disc_record[64];
    int normal_sector;
    int special_sector;

    inregs.r[0] = 0;                    /* might as well */
    inregs.r[1] = 4;                    /* write a track */
    inregs.r[1] = inregs.r[1] | ((int)disc_record << 6);             /* point to new disc record */

    inregs.r[2] = (((TRACK_NO * 2) + SIDE) * 6) *1024;               /* ie start of track ?? side ?? secot 0 etc.... */
    inregs.r[3] = 0;
    inregs.r[4] = (int) disc_format_block;      /* pointer to disc format structure */

    make_disc_record_E_Special(&disc_record[0]);

    *(int *)(disc_format_block +  0) = 1024;            /* size of sectors */
    *(int *)(disc_format_block +  4) = 100;             /* gap 1, for side 0 */
    *(int *)(disc_format_block +  8) = 32;              /* gap 1, for side 1 */
    *(int *)(disc_format_block + 12) = 72;              /* gap 3    */
    *(disc_format_block + 16)        = (char) 6;        /* sectors per track */
    *(disc_format_block + 17)        = (char) 2;        /* double density  */
    *(disc_format_block + 18)        = (char) 1;        /* flags, ie. force index mark & format side 1 only */
    *(disc_format_block + 19)        = (char) 0x00;     /* sector fill value */
    *(int *)(disc_format_block + 20) = 80;              /* 80 cylinders per dive */
    *(int *)(disc_format_block + 24) = 0;               /* Must be 0 */
    *(int *)(disc_format_block + 28) = 0;               /* Must be 0 */
    *(int *)(disc_format_block + 32) = 0;               /* Must be 0 */

    normal_sector  = (3 << 24) + (SIDE << 8) +TRACK_NO; /* cylinder number ??, head ??, 1K sectors */
    special_sector = (1 << 24) + (SIDE << 8) +TRACK_NO; /* cylinder number ??, head ??, 256 Byte sector */

    *(int *)(disc_format_block + 36) = normal_sector + (0 << 16);           /*  sector 0  */
    *(int *)(disc_format_block + 40) = normal_sector + (1 << 16);           /*  sector 1  */
    *(int *)(disc_format_block + 44) = normal_sector + (2 << 16);           /*  sector 2  */
    *(int *)(disc_format_block + 48) = normal_sector + (3 << 16);           /*  sector 3  */
    *(int *)(disc_format_block + 52) = normal_sector + (4 << 16);           /*  sector 4  */
    *(int *)(disc_format_block + 56) = special_sector + (SECTOR_ID << 16);  /*  sector ??  */

    _kernel_swi(ADFS_DiscOpErrors, &inregs, &outregs);
    return(0);
    }







/******************************************************************************/
/***                                                                        ***/
/***  make_disc_record_E_Special()                                          ***/
/***                                                                        ***/
/***  Makes up a disc record for the special format, for use when formatting***/
/***  only.                                                                 ***/
/***  The Special Record, is obtained from first reading the current ADFS   ***/
/***  format, then pretending that all tracks have 6 sectors of 1024 bytes  ***/
/***  in size. It then allows FILE CORE to format the correct part of the   ***/
/***  disc.                                                                 ***/
/***                                                                        ***/
/******************************************************************************/

void make_disc_record_E_Special(char *disc_record)
    {
    char disc_specifier[] = ":0";
    _kernel_swi_regs inregs, outregs;


    inregs.r[0] = (int) disc_specifier;
    inregs.r[1] = (int) disc_record;
    _kernel_swi(ADFS_DescribeDiscErrors, &inregs, &outregs);

    *(disc_record + 1) = (char) 6;
    *(int *)(disc_record + 16) = 0xF0000;
    }




/******************************************************************************/
/***                                                                        ***/
/***  SaveTrackData()                                                       ***/
/***                                                                        ***/
/***  Reads the entire track of data, which is about to be re-formatted.    ***/
/***  This can then be restored back to is original state.                  ***/
/***                                                                        ***/
/******************************************************************************/

void SaveTrackData(char *data)
    {
    _kernel_swi_regs inregs, outregs;

    inregs.r[0] = 0;                    /* might as well */
    inregs.r[1] = 1;                    /* Read Sectors  */

    inregs.r[2] = (((TRACK_NO * 2) + SIDE) * 5) *1024;               /* ie start of track ?? side ?? secot 0 etc.... */
    inregs.r[3] = (int) data;           /* address to store data */
    inregs.r[4] = (5 * 1024);           /* bytes to read */

    _kernel_swi(ADFS_DiscOpErrors, &inregs, &outregs);

    if (outregs.r[4] != 0)
        {
        printf("Error: Reading data from disc.\n\n\n");
        Belch();
        exit(255);
        }
    }



/******************************************************************************/
/***                                                                        ***/
/***  RestoreTrackData()                                                    ***/
/***                                                                        ***/
/***  Restores the track of data.                                           ***/
/***                                                                        ***/
/******************************************************************************/

void RestoreTrackData(char *data)
    {
    _kernel_swi_regs inregs, outregs;
    char disc_record[64];
    char disc_specifier[] = ":0";


    inregs.r[0] = (int) disc_specifier;
    inregs.r[1] = (int) disc_record;
    _kernel_swi(ADFS_DescribeDiscErrors, &inregs, &outregs);
    *(disc_record + 1) = (char) 5;
    *(int *)(disc_record + 16) = 0xC8000;


    inregs.r[0] = 0;                    /* might as well */
    inregs.r[1] = 2;                    /* Write Sectors  */
    inregs.r[1] = inregs.r[1] | ((int)disc_record << 6);             /* point to new disc record */

    inregs.r[2] = (((TRACK_NO * 2) + SIDE) * 5) *1024;               /* ie start of track ?? side ?? secot 0 etc.... */
    inregs.r[3] = (int) data;           /* address to store data */
    inregs.r[4] = (5 * 1024);           /* bytes to read */

    _kernel_swi(ADFS_DiscOpErrors, &inregs, &outregs);

    if (outregs.r[4] != 0)
        {
        printf("Error: Writing data to disc. (NB. Disc may be corrupt!)\n\n\n");
        Belch();
        exit(255);
        }
    }




/******************************************************************************/
/***                                                                        ***/
/***  system_type()                                                         ***/
/***                                                                        ***/
/***  Returns the system type being used. &A0 is Arther, &A1 = RISC OS 2.00 ***/
/***  &A2 = RISC OS 2.01, &A3 = RISC OS 3.                                  ***/
/***                                                                        ***/
/***  Returns:                                                              ***/
/***    Above value.                                                        ***/
/***    Or 0 if an error occured.                                           ***/
/***                                                                        ***/
/******************************************************************************/

int system_type()
    {
    _kernel_swi_regs inregs, outregs;

    inregs.r[0] = 0x81;
    inregs.r[1] = 0;
    inregs.r[2] = 0xFF;
    if (_kernel_swi(OS_Byte, &inregs, &outregs) != NULL)
        {
        outregs.r[1] = 0;
        }

    return(outregs.r[1]);
    }




